﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Fakes;
using Microsoft.Practices.Unity;
using Microsoft.QualityTools.Testing.Fakes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Sern.Abstracts.Tracker.DataContracts;
using Sern.Common;
using Sern.ServiceImplementation;
using Sern.ServiceImplementation.Fakes;
using Sern.ServiceImplementation.TrackerDefinition.Data;
using Sern.ServiceImplementation.TrackerDefinition.Service;

namespace Sern.Test.ServiceImplementation.TrackerDefinition.Service
{
    [Ignore]
    [Obsolete("Test listener must be started on and off by the host the inner class won't do that anymore - they'll also be stateless.")]
    [TestClass]
// ReSharper disable InconsistentNaming
    public class TrackerHost_CreateNewJobTracker
// ReSharper restore InconsistentNaming
    {
        readonly List<ClientListenerModel> _createdListeners = new List<ClientListenerModel>();

        [TestInitialize]
        public void Init()
        {
            ComponentLocator.Reset();

            new Sern.ServiceImplementation.LocalRegistrar().Register(ComponentLocator.Unity);

            ComponentLocator.Unity.RegisterTestInstance("SampleHostName","HostName");
            ComponentLocator.Unity.RegisterTestInstance<IEnumerable<string>>(new string[]{"Test","Hosting New Tracker"},"Keywords");
            ComponentLocator.Unity.RegisterTestInstance<string>("First tracker hosting test", "Description");

            ComponentLocator.Unity.RegisterInstance(
                RepositoryFactory.CreateStub<Client>());

            ComponentLocator.Unity.RegisterInstance(
                RepositoryFactory.CreateStub<ClientStatusInfo>());

            ComponentLocator.Unity.RegisterInstance(
                RepositoryFactory.CreateStub<Job>());

            ComponentLocator.Unity.RegisterInstance(
                RepositoryFactory.CreateStub<JobKeyword>());            

            ComponentLocator.Unity.RegisterInstance<IListenerFactory>(
                new StubIListenerFactory
                    {
                        CreateUriUriClientTypeObject = (baseUri, operationUri, clientType, instance)
                                                       =>
                            {
                                ComponentLocator.Unity.ResolveTest<Action<Uri, Uri, ClientType, object>>(
                                    "CreateUriCalledEventHandler")
                                    (baseUri, operationUri, clientType, instance);

                                return new Listener
                                    {
                                        Open = () =>
                                               ComponentLocator.Unity.ResolveTest<Action<Uri, Uri, ClientType, object>>(
                                                   "OpenListenerCalledEventHandler")(baseUri, operationUri, clientType,
                                                                                     instance),

                                        Close = () =>
                                                ComponentLocator.Unity.ResolveTest<Action<Uri, Uri, ClientType, object>>(
                                                    "CloseListenerCalledEventHandler")(baseUri, operationUri, clientType,
                                                                                       instance),

                                        Dispose = () => { }
                                    };
                            }
                    }
                );

            ComponentLocator.Unity.RegisterTestInstance<Action<Uri, Uri, ClientType, object>>(
                (baseUri, operationUri, clientType, instance) => _createdListeners.Add
                    (new ClientListenerModel
                    {
                        BaseUri = baseUri.AbsoluteUri,
                        OperationUri = operationUri.OriginalString,
                        ClientType = clientType,
                        ListenerState = ListenerState.Initialized,
                        SingletonInstance = instance
                    }), "CreateUriCalledEventHandler");

            ComponentLocator.Unity.RegisterTestInstance<Action<Uri, Uri, ClientType, object>>(
                (baseUri, operationUri, clientType, instance) => _createdListeners.Add
                    (new ClientListenerModel
                    {
                        BaseUri = baseUri.AbsoluteUri,
                        OperationUri = operationUri.OriginalString,
                        ClientType = clientType,
                        ListenerState = ListenerState.Opened,
                        SingletonInstance = instance
                    }), "OpenListenerCalledEventHandler");

            ComponentLocator.Unity.RegisterTestInstance<Action<Uri, Uri, ClientType, object>>(
                (baseUri, operationUri, clientType, instance) => _createdListeners.Add
                    (new ClientListenerModel
                    {
                        BaseUri = baseUri.AbsoluteUri,
                        OperationUri = operationUri.OriginalString,
                        ClientType = clientType,
                        ListenerState = ListenerState.Closed,
                        SingletonInstance = instance
                    }), "CloseListenerCalledEventHandler");

        }

        [TestMethod]
        public void TestListenersAreStarted()
        {
            var trackerHost = new TrackerHost(ComponentLocator.Unity.ResolveTest<string>("HostName"));            
            
            trackerHost.Initialize();

            Assert.IsTrue(_createdListeners.Any(l => l.ClientType == ClientType.TrackerHost && l.ListenerState == ListenerState.Initialized));
            Assert.IsTrue(_createdListeners.Any(l => l.ClientType == ClientType.TrackerHost && l.ListenerState == ListenerState.Opened));
            //Check that the new tracker exists in the fake persistence
            //Check that listeners are fired in a way that makes sense.
            //Check that keywords are correct. (This could be delegated to another class!

            trackerHost.StartANewJob(Guid.NewGuid(), ComponentLocator.Unity.ResolveTest<IEnumerable<string>>("Keywords"),
                ComponentLocator.Unity.ResolveTest<string>("Description"));


            Assert.IsTrue(_createdListeners.Any(l => l.ClientType == ClientType.Tracker && l.ListenerState == ListenerState.Initialized), "Tracker listener not initialized");
            Assert.IsTrue(_createdListeners.Any(l => l.ClientType == ClientType.Tracker && l.ListenerState == ListenerState.Opened), "Tracker listener not opened");

            Assert.IsTrue(_createdListeners.Any(l => l.ClientType == ClientType.TrackerTelemetry && l.ListenerState == ListenerState.Initialized), "Tracker telemetry not initialized");
            Assert.IsTrue(_createdListeners.Any(l => l.ClientType == ClientType.TrackerTelemetry && l.ListenerState == ListenerState.Opened), "Tracker telemetry not opened");


            //TODO: Check if the job is in the backing store
            
            //TODO: CHeck if tracker monitor g
        }

        [TestMethod]
        public void TestTrackersAndTelemetryAreRegistered()
        {
            var trackerHost = new TrackerHost(ComponentLocator.Unity.ResolveTest<string>("HostName"));

            trackerHost.Initialize();

            Assert.IsTrue(_createdListeners.Any(l => l.ClientType == ClientType.TrackerHost && l.ListenerState == ListenerState.Initialized));
            Assert.IsTrue(_createdListeners.Any(l => l.ClientType == ClientType.TrackerHost && l.ListenerState == ListenerState.Opened));
            //Check that the new tracker exists in the fake persistence
            //Check that listeners are fired in a way that makes sense.
            //Check that keywords are correct. (This could be delegated to another class!

            var jobId = Guid.NewGuid();

                trackerHost.StartANewJob(jobId, ComponentLocator.Unity.ResolveTest<IEnumerable<string>>("Keywords"),
                ComponentLocator.Unity.ResolveTest<string>("Description"));


            Assert.IsTrue(
                ComponentLocator.Unity.Resolve<IRepository<Job>>().Records.Any(c => c.Id == jobId)
                , "Job must be self registering.");

            Assert.IsTrue(
                ComponentLocator.Unity.Resolve<IRepository<Client>>().Records.Any(c => c.Type == (int)ClientType.TrackerTelemetry)
                , "Tracker telemetry must be self registering.");
        }
    }
}
